package com.digua.iot.confignetwork.base

import android.Manifest
import android.content.Context
import android.net.wifi.WifiManager
import android.os.Bundle
import android.os.SystemClock
import androidx.viewbinding.ViewBinding
import com.blankj.utilcode.util.NetworkUtils
import com.blankj.utilcode.util.NetworkUtils.OnNetworkStatusChangedListener
import com.digua.base.base.Activity
import com.digua.base.util.LogUtil
import com.digua.base.util.PerUtil
import com.digua.base.util.SPUtils
import com.digua.base.util.ThreadUtil
import com.digua.iot.confignetwork.MyApp
import com.digua.iot.confignetwork.config.Const
import com.digua.iot.confignetwork.entitiy.AirKissEncoder
import com.digua.iot.confignetwork.entitiy.HistoryWifi
import com.digua.iot.confignetwork.utils.HexUtils
import com.gyf.immersionbar.BarHide
import com.gyf.immersionbar.ImmersionBar
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
import java.util.Arrays

open class BaseActivity<UI : ViewBinding> : Activity<UI>(), OnNetworkStatusChangedListener {
    protected var wifiInfo = HistoryWifi()
    private var timeoutTime = 60000 //超时时间：60秒
    private var startTime = 0L
    private var sendSocket: DatagramSocket? = null
    private var receivedSocket: DatagramSocket? = null
    private var sendThread: Thread? = null
    private var receivedThread: Thread? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        MyApp.instance.addActivity(this)
        ImmersionBar.with(this).statusBarDarkFont(true).hideBar(BarHide.FLAG_HIDE_NAVIGATION_BAR).init()
        NetworkUtils.registerNetworkStatusChangedListener(this)
    }

    override fun onDestroy() {
        NetworkUtils.registerNetworkStatusChangedListener(this)
        super.onDestroy()
    }

    /**
     * 网络断开
     */
    override fun onDisconnected() {}

    /**
     * 网络连接
     */
    override fun onConnected(networkType: NetworkUtils.NetworkType) {}

    fun getWifiInfo(lambda: (HistoryWifi) -> Unit) {
        PerUtil.permission({//成功
            val data = HistoryWifi()
            val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
            val wifiInfo = wifiManager.connectionInfo
            data.bssid = wifiInfo.bssid
            val ssid = wifiInfo.ssid
            data.ssid = if (ssid.startsWith("\"") && ssid.endsWith("\"")) ssid.substring(1, ssid.length - 1) else ssid
            data.name = data.ssid
            data.pwd = SPUtils.getString(Const.SP_HISTORYWIFI + data.ssid)
            this.wifiInfo = data
            lambda(data)
        }, {//失败
            this.wifiInfo = HistoryWifi()
            lambda(wifiInfo)
        }, "获取权限失败", Manifest.permission.ACCESS_FINE_LOCATION)
    }

    fun onConfig(lambda: (Boolean, String) -> Unit) {
        startTime = System.currentTimeMillis()
        sendAirKiss(lambda)
        //receiveAirKiss(lambda)
    }

    //发送AirKiss
    private fun sendAirKiss(lambda: (Boolean, String) -> Unit) {
        sendThread = ThreadUtil.post {
            try {
                sendSocket = DatagramSocket()
                sendSocket?.let {
                    it.broadcast = true
                    val encodedData = AirKissEncoder(wifiInfo.ssid!!, wifiInfo.pwd!!).getEncodedData()
                    for (i in encodedData.indices) {
                        if (sendThread == null || sendSocket == null || it.isClosed) break
                        val pkg = DatagramPacket(ByteArray(1500), encodedData[i], InetAddress.getByName("255.255.255.255"), 10000)
                        it.send(pkg)
                        SystemClock.sleep(4)
                    }
                    runOnUiThread { lambda(true, "配置结束") }
                }
            } catch (e: Exception) {
                e.printStackTrace()
                runOnUiThread { lambda(false, "配置失败[${e.localizedMessage}]") }
            } finally {
                cancelConfig()
            }
        }
    }

    //接收udp AirKiss包
    private fun receiveAirKiss(lambda: (Boolean, String) -> Unit) {
        receivedThread = ThreadUtil.post {
            try {
                receivedSocket = DatagramSocket(18266)
                receivedSocket?.let {
                    it.reuseAddress = true
                    it.soTimeout = timeoutTime
                    val packet = DatagramPacket(ByteArray(64), 64)
                    while (true) {
                        it.receive(packet)
                        if (receivedThread == null || receivedSocket == null || it.isClosed) break
                        if (packet.data.isNotEmpty()) {
                            LogUtil.e("===packet.data: " + String(packet.data))
                        }
                        val recDatas = Arrays.copyOf(packet.data, packet.length)
                        LogUtil.e("===received len : " + recDatas.size)
                        for (i in recDatas.indices) {
                            LogUtil.e("===recDatas[" + i + "]:" + recDatas[i])
                        }
                        LogUtil.e("===receiveSpecLenBytes: " + String(recDatas))
                        val expectOneByte: Byte = (wifiInfo.ssid!!.length + wifiInfo.pwd!!.length + 9).toByte()
                        if (recDatas.size != (1 + 6 + 4)) {
                            LogUtil.e("===received len is different from specific len, return null")
                            runOnUiThread { lambda(false, "配置失败") }
                            return@post
                        } else if (recDatas[0] == expectOneByte) {
                            LogUtil.e("===receive correct broadcast")
                            if (System.currentTimeMillis() - timeoutTime > startTime) {
                                runOnUiThread { lambda(false, "配置超时") }
                                return@post
                            } else {
                                LogUtil.e("===mSocketServer's new timeout is $timeoutTime milliseconds")
                                //mSocketServer.setSoTimeout(timeout)
                                LogUtil.e("===receive correct broadcast")
                                val bssid = HexUtils.parseBssid(recDatas, 1, 6)
                                val inetAddress = HexUtils.parseInetAddr(recDatas, 1 + 6, 4)
                                LogUtil.e("===>bssid = ${bssid}; inetAddress = ${inetAddress?.hostAddress}")
                                runOnUiThread {
                                    if (bssid.isNotBlank() && inetAddress != null) {
                                        lambda(true, "配置成功")
                                    } else {
                                        lambda(false, "配置失败")
                                    }
                                }
                            }
                        }
                    }
                }
                runOnUiThread { lambda(true, "配置结束") }
            } catch (e: Exception) {
                e.printStackTrace()
                LogUtil.e("===>use time2 = ${System.currentTimeMillis() - startTime}")
                runOnUiThread { lambda(false, "配置失败[${e.localizedMessage}]") }
            } finally {
                cancelConfig()
            }
        }
    }

    fun cancelConfig() {
        sendSocket?.close()
        sendSocket?.disconnect()
        sendSocket = null

        sendThread?.interrupt()
        sendThread = null

        receivedSocket?.close()
        receivedSocket?.disconnect()
        receivedSocket = null

        receivedThread?.interrupt()
        receivedThread = null
    }

}